home *** CD-ROM | disk | FTP | other *** search
/ Atari Forever 4 / Atari Forever 4.zip / Atari Forever 4.iso / SERIE_AI / AI_018 / POVRAY3.LZH / 3DSPOV18 / SOURCE / 3DS2POV.C next >
C/C++ Source or Header  |  1995-05-20  |  67KB  |  2,834 lines

  1. /*
  2.       3DS2POV.C  Copyright (c) 1993 Steve Anger and Jeff Bowermaster
  3.  
  4.       Reads a 3D Studio .3DS file and writes a POV-Ray, Vivid, or
  5.       Polyray scene file.
  6.  
  7.       Version 1.8 Written Oct/93
  8.  
  9.       Compiled with MSDOS GNU C++ 2.4.1
  10. */
  11.  
  12. #define __GNUC__
  13. #undef __TURBOC__
  14.  
  15. #include <stdio.h>
  16. #include "portab.h"
  17. #include <stdlib.h>
  18. #include <math.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include "vect.h"
  22. #include "rayopt.h"
  23.  
  24. #ifdef __TURBOC__
  25. #include <alloc.h>
  26. extern unsigned _stklen = 16384;
  27. #endif
  28.  
  29. #define FALSE 0
  30. #define TRUE  1
  31.  
  32. /* Internal bounding modes */
  33. #define OFF  0
  34. #define ON   1
  35. #define AUTO 2
  36.  
  37. #define MAX_LIB  10
  38. #define ASPECT   1.333
  39.  
  40. /* Output formats */
  41. #define POV10    0
  42. #define POV20    1
  43. #define VIVID    2
  44. #define POLYRAY  3
  45. #define RAW      99
  46.  
  47. #define DEG(x) ((180.0/M_PI)*(x))
  48. #define RAD(x) ((M_PI/180.0)*(x))
  49.  
  50. #ifndef M_PI
  51. #define M_PI (3.1415926535)
  52. #endif
  53.  
  54. #ifndef MAXFLOAT
  55. #define MAXFLOAT (1e37)
  56. #endif
  57.  
  58. /* A generic list type */
  59. #define LIST_INSERT(root, node) list_insert ((List **)&root, (List *)node)
  60. #define LIST_FIND(root, name)   list_find   ((List **)&root, name)
  61. #define LIST_DELETE(root, node) list_delete ((List **)&root, (List *)node)
  62. #define LIST_KILL(root)         list_kill   ((List **)&root)
  63.  
  64. #define LIST_FIELDS  \
  65.     char name[80];   \
  66.     void *next;
  67.  
  68.  
  69. typedef unsigned char  byte;
  70. typedef unsigned short word;
  71. typedef unsigned long  dword;
  72.  
  73. typedef struct {
  74.     LIST_FIELDS
  75. } List;
  76.  
  77.  
  78. typedef struct {
  79.     int a, b, c;
  80. } Face;
  81.  
  82.  
  83. typedef struct {
  84.     float red, green, blue;
  85. } Colour;
  86.  
  87.  
  88. /* Transformation command */
  89. typedef struct {
  90.     LIST_FIELDS
  91.  
  92.     Matrix matrix;
  93. } Transform;
  94.  
  95.  
  96. /* Morph command */
  97. typedef struct {
  98.     LIST_FIELDS
  99.  
  100.     int    count;          /* Number of objects in morph */
  101.     char   names[4][80];   /* Name of n'th object in average */
  102.     float  weight[4];      /* Weight applied to n'th object */
  103.  
  104.     Matrix matrix;
  105. } Morph;
  106.  
  107.  
  108. /* Omni light command */
  109. typedef struct {
  110.     LIST_FIELDS
  111.  
  112.     Vector pos;            /* Light position */
  113.     Colour col;            /* Light colour */
  114. } OmniLight;
  115.  
  116.  
  117. /* Spotlight command */
  118. typedef struct {
  119.     LIST_FIELDS
  120.  
  121.     Vector pos;            /* Spotlight position */
  122.     Vector target;         /* Spotlight target location */
  123.     Colour col;            /* Spotlight colour */
  124.     float  hotspot;        /* Hotspot angle (degrees) */
  125.     float  falloff;        /* Falloff angle (degrees) */
  126.     int    shadow_flag;    /* Shadow flag (not used) */
  127. } Spotlight;
  128.  
  129.  
  130. /* Camera command */
  131. typedef struct {
  132.     LIST_FIELDS
  133.  
  134.     Vector pos;            /* Camera location */
  135.     Vector target;         /* Camera target */
  136.     float  bank;           /* Banking angle (degrees) */
  137.     float  lens;           /* Camera lens size (mm) */
  138. } Camera;
  139.  
  140.  
  141. /* Material list */
  142. typedef struct {
  143.     LIST_FIELDS
  144.  
  145.     int  external;         /* Externally defined material? */
  146. } Material;
  147.  
  148.  
  149. /* Object summary */
  150. typedef struct {
  151.     LIST_FIELDS
  152.  
  153.     Vector center;         /* Min value of object extents */
  154.     Vector lengths;        /* Max value of object extents */
  155. } Summary;
  156.  
  157.  
  158. /* Material property */
  159. typedef struct {
  160.     LIST_FIELDS
  161.  
  162.     Colour ambient;
  163.     Colour diffuse;
  164.     Colour specular;
  165.     float  shininess;
  166.     float  transparency;
  167.     float  reflection;
  168.     int    self_illum;
  169.     char   tex_map[40];
  170.     float  tex_strength;
  171.     char   bump_map[40];
  172.     float  bump_strength;
  173. } MatProp;
  174.  
  175.  
  176. /* Default material property */
  177. MatProp DefaultMaterial = { "Default", NULL, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0},
  178.                  {1.0, 1.0, 1.0}, 70.0, 0.0, 0.0, FALSE };
  179.  
  180. /* A mesh object */
  181. typedef struct {
  182.     LIST_FIELDS
  183.  
  184.     int  vertices;         /* Number of vertices */
  185.     Vector *vertex;        /* List of object vertices */
  186.  
  187.     int  faces;            /* Number of faces */
  188.     Face *face;            /* List of object faces */
  189.     Material **mtl;        /* Materials for each face */
  190.  
  191.     Matrix matrix;         /* Local mesh matrix */
  192.     Matrix invmatrix;
  193.     Vector center;         /* Center of object */
  194.     Vector lengths;        /* Dimensions of object */
  195.  
  196.     int hidden;            /* Hidden flag */
  197.     int shadow;            /* Shadow flag */
  198. } Mesh;
  199.  
  200.  
  201. typedef struct {
  202.     dword start;
  203.     dword end;
  204.     dword length;
  205.     word  tag;
  206. } Chunk;
  207.  
  208.  
  209. typedef struct {
  210.     byte red;
  211.     byte green;
  212.     byte blue;
  213. } Colour_24;
  214.  
  215.  
  216. Colour Black = {0.0, 0.0, 0.0};
  217.  
  218. OmniLight *omni_list  = NULL;
  219. Spotlight *spot_list  = NULL;
  220. Camera    *cam_list   = NULL;
  221. Mesh      *mesh_list  = NULL;
  222. Transform *trans_list = NULL;
  223. Morph     *morph_list = NULL;
  224. Material  *mtl_list   = NULL;
  225. List      *excl_list  = NULL;
  226. List      *box_list   = NULL;
  227. MatProp   *mprop_list = NULL;
  228. Summary   *summary    = NULL;
  229.  
  230.  
  231. FILE   *in;
  232. FILE   *out;
  233. char   inname[80];
  234. char   outname[80];
  235. char   vuename[80];
  236. char   obj_name[80] = "";
  237. Colour fog_colour = {0.0, 0.0, 0.0};
  238. Colour col        = {0.0, 0.0, 0.0};
  239. Colour global_amb = {0.1, 0.1, 0.1};
  240. Vector pos        = {0.0, 0.0, 0.0};
  241. Vector target     = {0.0, 0.0, 0.0};
  242. float  fog_distance = 0.0;
  243. float  hotspot = -1;
  244. float  falloff = -1;
  245. Mesh   *mesh = NULL;
  246. int    frame = -1;
  247. char   libname[MAX_LIB][80];
  248. float  smooth = 60.0;
  249. int    bound = 0;
  250. int    verbose = 0;
  251. int    format = POV20;
  252. int    internal_bounding = AUTO;
  253. int    box_all = FALSE;
  254. int    cameras = 0;
  255. int    libs = 0;
  256. float  vue_version = 1.0;
  257. Matrix *ani_matrix = NULL;
  258.  
  259.  
  260. void process_args (int argc, char *argv[]);
  261. void parse_option (char *option);
  262. void list_insert (List **root, List *new_node);
  263. void *list_find (List **root, char *name);
  264. void list_delete (List **root, List *node);
  265. void list_kill (List **root);
  266. Material *update_materials (char *new_material, int ext);
  267. MatProp *create_mprop (void);
  268. void read_library (char *fname);
  269. void write_intro (FILE *f);
  270. void write_summary (FILE *f);
  271. void write_bgsolid (FILE *f, Colour col);
  272. void write_light (FILE *f, char *name, Vector pos, Colour col);
  273. void write_spot (FILE *f, char *name, Vector pos, Vector target, Colour col,
  274.      float hotspot, float falloff);
  275. void write_fog (FILE *f, Colour col, float dist);
  276. void write_camera (FILE *f, char *name, Vector pos, Vector target, float lens,
  277.      float bank);
  278. void write_material (FILE *f, char *mat);
  279. void write_pov10_material (FILE *f, MatProp *m);
  280. void write_pov20_material (FILE *f, MatProp *m);
  281. void write_vivid_material (FILE *f, MatProp *m);
  282. void write_polyray_material (FILE *f, MatProp *m);
  283. void write_mesh (FILE *f, Mesh *mesh);
  284. Transform *parse_transform (char *string);
  285. Morph *parse_morph (char *string);
  286. OmniLight *parse_omnilight (char *string);
  287. Spotlight *parse_spotlight (char *string);
  288. Camera *parse_camera (char *string);
  289. void read_frame (char *filename, int frame_no);
  290. void find_frame (FILE *f, int frame_no);
  291. void save_animation (void);
  292. Mesh *create_mesh (char *name, int vertices, int faces);
  293. Mesh *copy_mesh (Mesh *mesh);
  294. void free_mesh_data (Mesh *mesh);
  295. void update_limits (Mesh *mesh);
  296. char *before (char *str, char *target);
  297. char *after (char *str, char *target);
  298. char *between (char *str, char *target1, char *target2);
  299. char *parse_string (char *str);
  300. char upcase (char c);
  301. float colour_intens (Colour *colour);
  302. void parse_file (void);
  303. void parse_3ds (Chunk *mainchunk);
  304. void parse_mdata (Chunk *mainchunk);
  305. void parse_fog (Chunk *mainchunk);
  306. void parse_fog_bgnd (void);
  307. void parse_mat_entry (Chunk *mainchunk);
  308. char *parse_mapname (Chunk *mainchunk);
  309. void parse_named_object (Chunk *mainchunk);
  310. void parse_n_tri_object (Chunk *mainchunk);
  311. void parse_point_array (void);
  312. void parse_face_array (Chunk *mainchunk);
  313. void parse_msh_mat_group (void);
  314. void parse_smooth_group (void);
  315. void parse_mesh_matrix (void);
  316. void parse_n_direct_light (Chunk *mainchunk);
  317. void parse_dl_spotlight (void);
  318. void parse_n_camera (void);
  319. void parse_colour (Colour *colour);
  320. void parse_colour_f (Colour *colour);
  321. void parse_colour_24 (Colour_24 *colour);
  322. float parse_percentage (void);
  323. short parse_int_percentage (void);
  324. float parse_float_percentage (void);
  325. void start_chunk (Chunk *chunk);
  326. void end_chunk (Chunk *chunk);
  327.  
  328. byte read_byte (void);
  329. word read_word (void);
  330. dword read_dword (void);
  331. float read_float (void);
  332. void read_point (Vector v);
  333. char *read_string (void);
  334. float findfov (float lens);
  335.  
  336.  
  337. int main (int argc, char *argv[])
  338. {
  339.     Material *m;
  340.     int i;
  341.  
  342.     process_args (argc, argv);
  343.  
  344.     if (format != RAW) {
  345.     opt_set_format (format);
  346.     opt_set_dec (4);
  347.     opt_set_bound (bound);
  348.     opt_set_smooth (smooth);
  349.     opt_set_quiet (!verbose);
  350.     opt_set_fname (outname, "");
  351.     }
  352.  
  353.     if ((in = fopen (inname, "rb")) == NULL) {
  354.     printf ("Cannot open input file %s!\n", inname);
  355.     exit (1);
  356.     }
  357.  
  358.     if ((out = fopen (outname, "w")) == NULL) {
  359.     printf ("Cannot open output file %s!\n", outname);
  360.     exit (1);
  361.     }
  362.  
  363.     /* Load the names of pre-defined materials */
  364.     for (i = 0; i < MAX_LIB; i++) {
  365.     if (strlen(libname[i]) > 0)
  366.         read_library (libname[i]);
  367.     }
  368.  
  369.     /* Load the instructions for the current frame */
  370.     if (strlen(vuename) > 0)
  371.     read_frame (vuename, frame);
  372.  
  373.     printf("Output to: %s\n", outname);
  374.  
  375.     if (frame >= 0)
  376.     printf ("Generating frame #%d\n", frame);
  377.  
  378.     printf("\nPlease wait; Processing...\n");
  379.  
  380.     write_intro(out);
  381.  
  382.     parse_file();
  383.  
  384.     fclose(in);
  385.  
  386.     for (m = mtl_list; m != NULL; m = m->next) {
  387.     if (!m->external)
  388.         write_material (out, m->name);
  389.     }
  390.  
  391.     fclose (out);
  392.  
  393.     if (frame >= 0)
  394.     save_animation();
  395.  
  396.     if (format != RAW) {
  397.         out = fopen (outname, "a");
  398.         write_summary (out);
  399.         fclose (out);
  400.  
  401.     opt_finish();
  402.     }
  403.  
  404.     LIST_KILL (omni_list);
  405.     LIST_KILL (spot_list);
  406.     LIST_KILL (cam_list);
  407.     LIST_KILL (mesh_list);
  408.     LIST_KILL (trans_list);
  409.     LIST_KILL (morph_list);
  410.     LIST_KILL (mtl_list);
  411.     LIST_KILL (excl_list);
  412.     LIST_KILL (box_list);
  413.     LIST_KILL (mprop_list);
  414.     LIST_KILL (summary);
  415.  
  416.     return 0;
  417. }
  418.  
  419.  
  420. /* Handle the command line args */
  421. void process_args (int argc, char *argv[])
  422. {
  423.     int i;
  424.     char *env_opt, *option;
  425.  
  426.     printf("\n\nAutodesk 3D Studio to Raytracer file Translator. Oct/93\n");
  427.     printf("Version 1.8 Copyright (c) 1993 Steve Anger and Jeff Bowermaster\n");
  428. #ifdef __GNUC__
  429.     printf ("32 bit version. DOS extender Copyright (c) 1991 DJ Delorie\n");
  430. #endif
  431.     printf ("\n");
  432.  
  433.     if (argc < 2) {
  434.     printf ("Usage: 3ds2pov inputfile[.3ds] [outputfile] [options]\n\n");
  435.     printf ("Options: -snnn        - Smooth triangles with angles < nnn\n");
  436.     printf ("         -l<filename> - Specifies 3DS texture library\n");
  437.     printf ("         -a<filename> - Use animation information in specified file\n");
  438.     printf ("         -fnnn        - Generate frame nnn of animation\n");
  439.     printf ("         -x<object>   - Exclude this object from conversion\n");
  440.     printf ("         -b<object>   - Convert this object as a box\n");
  441.     printf ("         +i, -i       - Turn internal bounding on or off\n");
  442.     printf ("         +v, -v       - Turn verbose status messages on or off\n");
  443.     printf ("         -op          - Output to POV-Ray 2.0 format (default)\n");
  444.     printf ("         -op1         - Output to POV-Ray 1.0 format\n");
  445.     printf ("         -ov          - Output to Vivid format\n");
  446.     printf ("         -ol          - Output to poLyray format\n");
  447.     printf ("         -or          - Output to RAW triangle format\n\n");
  448.     printf ("ex. 3ds2pov birdshow +v -l3ds.inc\n\n");
  449.     exit(1);
  450.     }
  451.  
  452.     strcpy (inname, "");
  453.     strcpy (outname, "");
  454.     strcpy (vuename, "");
  455.  
  456.     for (i = 0; i < MAX_LIB; i++)
  457.     strcpy (libname[i], "");
  458.  
  459.     frame = -1;
  460.     smooth = 70.0;
  461.     bound = 0;
  462.     verbose = 0;
  463.     format = POV20;
  464.     internal_bounding = AUTO;
  465.     box_all = FALSE;
  466.     libs = 0;
  467.  
  468.     /* Parse the enviroment string options */
  469.     env_opt = getenv ("3DS2POV");
  470.  
  471.     if (env_opt != NULL) {
  472.     option = parse_string (env_opt);
  473.  
  474.     while (strlen(option) > 0) {
  475.         parse_option (option);
  476.         option = parse_string (NULL);
  477.     }
  478.     }
  479.  
  480.     /* Parse the command line options */
  481.     for (i = 1; i < argc; i++)
  482.     parse_option (argv[i]);
  483.  
  484.     if (strlen(inname) == 0)
  485.     abortmsg ("No input file specified", 1);
  486.  
  487.     if (strlen(outname) == 0) {
  488.     strcpy (outname, inname);
  489.  
  490.     switch (format) {
  491.         case POV10:
  492.         case POV20:   add_ext (outname, "pov", 1); break;
  493.         case VIVID:   add_ext (outname, "v",   1); break;
  494.         case POLYRAY: add_ext (outname, "pi",  1); break;
  495.         case RAW:     add_ext (outname, "raw", 1); break;
  496.     }
  497.     }
  498.     else {
  499.     switch (format) {
  500.         case POV10:
  501.         case POV20:   add_ext (outname, "pov", 0); break;
  502.         case VIVID:   add_ext (outname, "v",   0); break;
  503.         case POLYRAY: add_ext (outname, "pi",  0); break;
  504.         case RAW:     add_ext (outname, "raw", 0); break;
  505.     }
  506.     }
  507.  
  508.     switch (internal_bounding) {
  509.     case OFF:  bound = 2; break;
  510.     case ON:   bound = 0; break;
  511.     case AUTO: bound = (format == POV10) ? 0 : 2; break;
  512.     }
  513.  
  514.     if ((strlen(vuename) > 0) != (frame >= 0))
  515.     abortmsg ("The -a and -f parameters must be used together", 1);
  516. }
  517.  
  518.  
  519. void parse_option (char *option)
  520. {
  521.     List *excl, *box;
  522.     char name[80];
  523.  
  524.     if (option[0] == '-' || option[0] == '+') {
  525.     switch (upcase(option[1])) {
  526.         case 'A': strcpy (vuename, &option[2]);
  527.               break;
  528.  
  529.         case 'B': strcpy (name, parse_string (&option[2]));
  530.               if (strlen(name) == 0)
  531.               box_all = TRUE;
  532.               else {
  533.               cleanup_name (name);
  534.  
  535.               box = malloc (sizeof (*box));
  536.               strcpy (box->name, name);
  537.  
  538.               LIST_INSERT (box_list, box);
  539.               }
  540.               break;
  541.  
  542.         case 'F': if (option[2] != '\0')
  543.               frame = atoi (&option[2]);
  544.               break;
  545.  
  546.         case 'I': if (option[0] == '-')
  547.               internal_bounding = OFF;
  548.               else
  549.               internal_bounding = ON;
  550.               break;
  551.  
  552.         case 'L': if (libs == MAX_LIB)
  553.               abortmsg ("Too many libraries specified", 1);
  554.  
  555.               strcpy (libname[libs++], &option[2]);
  556.               break;
  557.  
  558.         case 'O': switch (upcase(option[2])) {
  559.               case 'P': if (option[3] == '1')
  560.                     format = POV10;
  561.                     else
  562.                     format = POV20;
  563.                     break;
  564.  
  565.               case 'V': format = VIVID;
  566.                     break;
  567.  
  568.               case 'L': format = POLYRAY;
  569.                     break;
  570.  
  571.               case 'R': format = RAW;
  572.                     break;
  573.  
  574.               default:  printf ("Invalid output format %s specified\n", option);
  575.                     exit(1);
  576.               }
  577.               break;
  578.  
  579.         case 'S': if (option[2] != '\0')
  580.               smooth = atof (&option[2]);
  581.               break;
  582.  
  583.         case 'U': printf ("Warning: -u parameter no long has any effect\n");
  584.               printf ("         use +i or -i instead.\n");
  585.               break;
  586.  
  587.         case 'V': if (option[0] == '-')
  588.               verbose = 0;
  589.               else
  590.               verbose = 1;
  591.               break;
  592.  
  593.         case 'X': strcpy (name, parse_string (&option[2]));
  594.               cleanup_name (name);
  595.  
  596.               excl = malloc (sizeof (*excl));
  597.               strcpy (excl->name, name);
  598.  
  599.               LIST_INSERT (excl_list, excl);
  600.               break;
  601.  
  602.         default : printf ("\nInvalid option %s specified\n", option);
  603.               exit (1);
  604.     }
  605.     }
  606.     else if (strlen (inname) == 0) {
  607.     strcpy (inname, option);
  608.     add_ext (inname, "3ds", 0);
  609.     }
  610.     else if (strlen (outname) == 0)
  611.     strcpy (outname, option);
  612.     else
  613.     abortmsg ("Too many file names specified.\n", 1);
  614. }
  615.  
  616.  
  617. /* Insert a new node into the list */
  618. void list_insert (List **root, List *new_node)
  619. {
  620.     new_node->next = *root;
  621.  
  622.     *root = new_node;
  623. }
  624.  
  625.  
  626. /* Find the node with the specified name */
  627. void *list_find (List **root, char *name)
  628. {
  629.     List *p;
  630.  
  631.     for (p = *root; p != NULL; p = p->next) {
  632.     if (strcmp (p->name, name) == 0)
  633.         break;
  634.     }
  635.  
  636.     return (void *)p;
  637. }
  638.  
  639.  
  640. /* Delete the indicated node from the list */
  641. void list_delete (List **root, List *node)
  642. {
  643.     List *prev;
  644.  
  645.     prev = *root;
  646.     while (prev != NULL && prev->next != node)
  647.     prev = prev->next;
  648.  
  649.     if (prev == NULL)
  650.     *root = node->next;
  651.     else
  652.     prev->next = node->next;
  653.  
  654.     free (node);
  655. }
  656.  
  657.  
  658. /* Delete the entire list */
  659. void list_kill (List **root)
  660. {
  661.     List *temp;
  662.  
  663.     while (*root != NULL) {
  664.     temp = *root;
  665.     *root = (*root)->next;
  666.     free (temp);
  667.     }
  668. }
  669.  
  670.  
  671. /* Add a new material to the material list */
  672. Material *update_materials (char *new_material, int ext)
  673. {
  674.     Material *p;
  675.  
  676.     p = LIST_FIND (mtl_list, new_material);
  677.  
  678.     if (p == NULL) {
  679.     p = malloc (sizeof (*p));
  680.  
  681.     if (p == NULL)
  682.         abortmsg ("Out of memory adding material", 1);
  683.  
  684.     strcpy (p->name, new_material);
  685.     p->external = ext;
  686.  
  687.     LIST_INSERT (mtl_list, p);
  688.     }
  689.  
  690.     return p;
  691. }
  692.  
  693.  
  694. MatProp *create_mprop()
  695. {
  696.     MatProp *new_mprop;
  697.  
  698.     new_mprop = malloc (sizeof(*new_mprop));
  699.     if (new_mprop == NULL)
  700.     abortmsg ("Out of memory adding material", 1);
  701.  
  702.     strcpy (new_mprop->name, "");
  703.     new_mprop->ambient = Black;
  704.     new_mprop->diffuse = Black;
  705.     new_mprop->specular = Black;
  706.     new_mprop->shininess = 0.0;
  707.     new_mprop->transparency = 0.0;
  708.     new_mprop->reflection = 0.0;
  709.     new_mprop->self_illum = FALSE;
  710.  
  711.     strcpy (new_mprop->tex_map, "");
  712.     new_mprop->tex_strength = 0.0;
  713.  
  714.     strcpy (new_mprop->bump_map, "");
  715.     new_mprop->bump_strength = 0.0;
  716.  
  717.     return new_mprop;
  718. }
  719.  
  720.  
  721. /* Load in any predefined materials */
  722. void read_library (char *fname)
  723. {
  724.     FILE *lib;
  725.     char string[256], name[80];
  726.  
  727.     if ((lib = fopen (fname, "r")) == NULL) {
  728.     printf ("Cannot open texture library file %s!\n", fname);
  729.     exit(1);
  730.     }
  731.  
  732.     switch (format) {
  733.     case POV10:
  734.     case POV20:
  735.         while (fgets (string, 256, lib) != NULL) {
  736.         if (strstr (string, "#declare")) {
  737.             strcpy (name, between (string, "#declare", "="));
  738.             cleanup_name (name);
  739.             (void)update_materials (name, TRUE);
  740.         }
  741.         }
  742.         break;
  743.  
  744.     case VIVID:
  745.         while (fgets (string, 256, lib) != NULL) {
  746.         if (strstr (string, "#define")) {
  747.             (void)parse_string (string);
  748.             strcpy (name, parse_string (NULL));
  749.             cleanup_name (name);
  750.             (void)update_materials (name, TRUE);
  751.         }
  752.         }
  753.         break;
  754.  
  755.     case POLYRAY:
  756.         while (fgets (string, 256, lib) != NULL) {
  757.         if (strstr (string, "define")) {
  758.             (void)parse_string (string);
  759.             strcpy (name, parse_string (NULL));
  760.             cleanup_name (name);
  761.             (void)update_materials (name, TRUE);
  762.         }
  763.         }
  764.         break;
  765.     }
  766.  
  767.     fclose (lib);
  768. }
  769.  
  770.  
  771. void write_intro (FILE *f)
  772. {
  773.     int i;
  774.  
  775.     switch (format) {
  776.     case POV10:
  777.     case POV20:
  778.         fprintf (f, "#include \"colors.inc\"\n");
  779.         fprintf (f, "#include \"shapes.inc\"\n");
  780.         fprintf (f, "#include \"textures.inc\"\n");
  781.  
  782.         for (i = 0; i < MAX_LIB; i++) {
  783.         if (strlen(libname[i]) > 0)
  784.             fprintf (f, "#include \"%s\"\n", libname[i]);
  785.         }
  786.  
  787.         fprintf (f, "\n");
  788.         break;
  789.  
  790.     case VIVID:
  791.         fprintf (f, "#include color.vc\n");
  792.  
  793.         for (i = 0; i < MAX_LIB; i++) {
  794.         if (strlen(libname[i]) > 0)
  795.             fprintf (f, "#include %s\n", libname[i]);
  796.         }
  797.  
  798.         fprintf (f, "\n");
  799.         break;
  800.  
  801.     case POLYRAY:
  802.         fprintf (f, "include \"colors.inc\"\n");
  803.  
  804.         for (i = 0; i < MAX_LIB; i++) {
  805.         if (strlen(libname[i]) > 0)
  806.             fprintf (f, "include \"%s\"\n", libname[i]);
  807.         }
  808.  
  809.         fprintf (f, "\n");
  810.         break;
  811.     }
  812. }
  813.  
  814.  
  815. /* Write the object summary */
  816. void write_summary (FILE *f)
  817. {
  818.     Summary *s;
  819.  
  820.     if (summary == NULL)
  821.         return;
  822.  
  823.     fprintf (f, "//   Object    CenterX    CenterY    CenterZ    LengthX    LengthY    LengthZ\n");
  824.     fprintf (f, "// ---------- ---------- ---------- ---------- ---------- ---------- ----------\n");
  825.  
  826.     for (s = summary; s != NULL; s = s->next) {
  827.         fprintf (f, "// %-10s%11.2f%11.2f%11.2f%11.2f%11.2f%11.2f\n",
  828.          s->name, s->center[X], s->center[Y], s->center[Z],
  829.          s->lengths[X], s->lengths[Y], s->lengths[Z]);
  830.     }
  831.  
  832.     fprintf (f, "\n");
  833. }
  834.  
  835.  
  836. /* Write background solid colour */
  837. void write_bgsolid (FILE *f, Colour col)
  838. {
  839.     switch (format) {
  840.     case POV10:
  841.         fprintf (f, "/* Background colour */\n");
  842.         fprintf (f, "object {\n");
  843.         fprintf (f, "   sphere { <0.0 0.0 0.0> 1e6 }\n");
  844.         fprintf (f, "   texture {\n");
  845.         fprintf (f, "      ambient 1.0\n");
  846.         fprintf (f, "      diffuse 0.0\n");
  847.         fprintf (f, "      color red %4.2f green %4.2f blue %4.2f\n",
  848.                  col.red, col.green, col.blue);
  849.         fprintf (f, "   }\n");
  850.         fprintf (f, "}\n\n");
  851.         break;
  852.  
  853.     case POV20:
  854.         fprintf (f, "background { color red %4.2f green %4.2f blue %4.2f }\n\n",
  855.                col.red, col.green, col.blue);
  856.         break;
  857.  
  858.     case POLYRAY:
  859.         fprintf (f, "background <%4.2f, %4.2f, %4.2f>\n\n",
  860.                col.red, col.green, col.blue);
  861.         break;
  862.     }
  863. }
  864.  
  865.  
  866. void write_light (FILE *f, char *name, Vector pos, Colour col)
  867. {
  868.     switch (format) {
  869.     case POV10:
  870.         fprintf (f, "/* Light: %s */\n", name);
  871.         fprintf (f, "object {\n");
  872.         fprintf (f, "    light_source { <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f }\n",
  873.             pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
  874.         fprintf (f, "}\n\n");
  875.         break;
  876.  
  877.     case POV20:
  878.         fprintf (f, "/* Light: %s */\n", name);
  879.         fprintf (f, "light_source {\n");
  880.         fprintf (f, "    <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
  881.              pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
  882.         fprintf (f, "}\n\n");
  883.         break;
  884.  
  885.     case VIVID:
  886.         fprintf (f, "/* Light: %s */\n", name);
  887.         fprintf (f, "light {\n");
  888.         fprintf (f, "    type point\n");
  889.         fprintf (f, "    position %.4f %.4f %.4f\n",
  890.                  pos[X], pos[Y], pos[Z]);
  891.         fprintf (f, "    color %4.2f %4.2f %4.2f\n",
  892.                  col.red, col.green, col.blue);
  893.         fprintf (f, "}\n\n");
  894.         break;
  895.  
  896.     case POLYRAY:
  897.         fprintf (f, "// Light: %s\n", name);
  898.         fprintf (f, "light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>\n\n",
  899.              col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
  900.         break;
  901.     }
  902. }
  903.  
  904.  
  905. void write_spot (FILE *f, char *name, Vector pos, Vector target, Colour col,
  906.               float hotspot, float falloff)
  907. {
  908.     switch (format) {
  909.     case POV10:
  910.         fprintf (f, "/* Spotlight: %s */\n", name);
  911.         fprintf (f, "object {\n");
  912.         fprintf (f, "    light_source {\n");
  913.         fprintf (f, "        <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f\n",
  914.                    pos[X], pos[Y], pos[Z],
  915.                    col.red, col.green, col.blue);
  916.         fprintf (f, "        spotlight\n");
  917.         fprintf (f, "        point_at <%.4f %.4f %.4f>\n",
  918.                    target[X], target[Y], target[Z]);
  919.         fprintf (f, "        tightness 0\n");
  920.         fprintf (f, "        radius %.2f\n", 0.5*hotspot);
  921.         fprintf (f, "        falloff %.2f\n", 0.5*falloff);
  922.         fprintf (f, "    }\n");
  923.         fprintf (f, "}\n\n");
  924.         break;
  925.  
  926.     case POV20:
  927.         fprintf (f, "/* Spotlight: %s */\n", name);
  928.         fprintf (f, "light_source {\n");
  929.         fprintf (f, "    <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
  930.                  pos[X], pos[Y], pos[Z],
  931.                  col.red, col.green, col.blue);
  932.         fprintf (f, "    spotlight\n");
  933.         fprintf (f, "    point_at <%.4f, %.4f, %.4f>\n",
  934.                  target[X], target[Y], target[Z]);
  935.         fprintf (f, "    tightness 0\n");
  936.         fprintf (f, "    radius %.2f\n", 0.5*hotspot);
  937.         fprintf (f, "    falloff %.2f\n", 0.5*falloff);
  938.         fprintf (f, "}\n\n");
  939.         break;
  940.  
  941.     case VIVID:
  942.         fprintf (f, "/* Spotlight: %s */\n", name);
  943.         fprintf (f, "light {\n");
  944.         fprintf (f, "    type spot\n");
  945.         fprintf (f, "    position %.4f %.4f %.4f\n",
  946.                  pos[X], pos[Y], pos[Z]);
  947.         fprintf (f, "    at %.4f %.4f %.4f\n",
  948.                  target[X], target[Y], target[Z]);
  949.         fprintf (f, "    color %4.2f %4.2f %4.2f\n",
  950.                  col.red, col.green, col.blue);
  951.         fprintf (f, "    min_angle %.2f\n", hotspot);
  952.         fprintf (f, "    max_angle %.2f\n", falloff);
  953.         fprintf (f, "}\n\n");
  954.         break;
  955.  
  956.     case POLYRAY:
  957.         fprintf (f, "// Spotlight: %s\n", name);
  958.         fprintf (f, "spot_light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>,\n",
  959.               col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
  960.         fprintf (f, "           <%.4f, %.4f, %.4f>, 0.0, %.2f, %.2f\n\n",
  961.               target[X], target[Y], target[Z], hotspot/2.0, falloff/2.0);
  962.         break;
  963.     }
  964. }
  965.  
  966.  
  967. void write_fog (FILE *f, Colour col, float dist)
  968. {
  969.     if (dist <= 0.0)
  970.     return;
  971.  
  972.     switch (format) {
  973.     case POV10:
  974.         fprintf (f, "fog {\n");
  975.         fprintf (f, "    color red %4.2f green %4.2f blue %4.2f %.4f\n",
  976.               col.red, col.green, col.blue, dist/2.0);
  977.         fprintf (f, "}\n\n");
  978.         break;
  979.  
  980.     case POV20:
  981.         fprintf (f, "fog {\n");
  982.         fprintf (f, "    color red %4.2f green %4.2f blue %4.2f distance %.4f\n",
  983.               col.red, col.green, col.blue, dist/2.0);
  984.         fprintf (f, "}\n\n");
  985.         break;
  986.     }
  987. }
  988.  
  989.  
  990. void write_camera (FILE *f, char *name, Vector pos, Vector target,
  991.                 float lens, float bank)
  992. {
  993.     float fov;
  994.  
  995.     cameras++;
  996.  
  997.     fov = findfov (lens);
  998.  
  999.     switch (format) {
  1000.     case POV10:
  1001.         /* Comment out multiple cameras */
  1002.         if (cameras > 1)
  1003.         fprintf (f, "/*\n");
  1004.  
  1005.         fprintf (f, "/* Camera: %s */\n", name);
  1006.         fprintf (f, "camera {\n");
  1007.         fprintf (f, "   location <%.4f %.4f %.4f>\n",
  1008.                   pos[X], pos[Y], pos[Z]);
  1009.         fprintf (f, "   direction <0 %.3f 0>\n", 0.60/tan(0.5*RAD(fov)) );
  1010.         fprintf (f, "   up <0 0 1>\n");
  1011.         fprintf (f, "   sky  <0 0 1>\n");
  1012.         fprintf (f, "   right <%.3f 0 0>\n", ASPECT);
  1013.         fprintf (f, "   look_at <%.4f %.4f %.4f>\n",
  1014.                   target[X], target[Y], target[Z]);
  1015.         if (bank != 0.0)
  1016.         fprintf (f, "   /* Bank angle = %.2f */\n", bank);
  1017.  
  1018.         fprintf (f, "}\n");
  1019.  
  1020.         if (cameras > 1)
  1021.         fprintf (f, "*/\n");
  1022.  
  1023.         fprintf (f, "\n");
  1024.         break;
  1025.  
  1026.     case POV20:
  1027.         /* Comment out multiple cameras */
  1028.         if (cameras > 1)
  1029.         fprintf (f, "/*\n");
  1030.  
  1031.         fprintf (f, "/* Camera: %s */\n", name);
  1032.         fprintf (f, "camera {\n");
  1033.         fprintf (f, "   location <%.4f, %.4f, %.4f>\n",
  1034.                   pos[X], pos[Y], pos[Z]);
  1035.         fprintf (f, "   direction <0, %.3f, 0>\n", 0.60/tan(0.5*RAD(fov)) );
  1036.         fprintf (f, "   up <0, 0, 1>\n");
  1037.         fprintf (f, "   sky  <0, 0, 1>\n");
  1038.         fprintf (f, "   right <%.3f, 0, 0>\n", ASPECT);
  1039.         fprintf (f, "   look_at <%.4f, %.4f, %.4f>\n",
  1040.                   target[X], target[Y], target[Z]);
  1041.         if (bank != 0.0)
  1042.         fprintf (f, "   /* Bank angle = %.2f */\n", bank);
  1043.  
  1044.         fprintf (f, "}\n");
  1045.  
  1046.         if (cameras > 1)
  1047.         fprintf (f, "*/\n");
  1048.  
  1049.         fprintf (f, "\n");
  1050.         break;
  1051.  
  1052.     case VIVID:
  1053.         fprintf (f, "/* Camera: %s */\n", name);
  1054.  
  1055.         if (cameras > 1)
  1056.         fprintf (f, "/*\n");
  1057.  
  1058.         fprintf (f, "studio {\n");
  1059.         fprintf (f, "    from %.4f %.4f %.4f\n",
  1060.                    pos[X], pos[Y], pos[Z]);
  1061.         fprintf (f, "    at %.4f %.4f %.4f\n",
  1062.                    target[X], target[Y], target[Z]);
  1063.         fprintf (f, "    up 0 0 1\n");
  1064.         fprintf (f, "    angle %.2f\n", 1.1*fov);
  1065.         fprintf (f, "    aspect %.3f\n", ASPECT);
  1066.         fprintf (f, "    resolution 320 200\n");
  1067.         fprintf (f, "    antialias none\n");
  1068.         fprintf (f, "}\n");
  1069.  
  1070.         if (cameras > 1)
  1071.         fprintf (f, "*/\n");
  1072.  
  1073.         fprintf (f, "\n");
  1074.         break;
  1075.  
  1076.     case POLYRAY:
  1077.         if (cameras == 1) {
  1078.         fprintf (f, "// Camera: %s\n", name);
  1079.         fprintf (f, "viewpoint {\n");
  1080.         fprintf (f, "    from <%.4f, %.4f, %.4f>\n",
  1081.                    pos[X], pos[Y], pos[Z]);
  1082.         fprintf (f, "    at <%.4f, %.4f, %.4f>\n",
  1083.                    target[X], target[Y], target[Z]);
  1084.         fprintf (f, "    up <0, 0, 1>\n");
  1085.         fprintf (f, "    angle %.2f\n", 0.85*fov);
  1086.         fprintf (f, "    aspect %.3f\n", -(ASPECT));
  1087.         fprintf (f, "    resolution 320, 200\n");
  1088.         fprintf (f, "}\n");
  1089.         }
  1090.  
  1091.         fprintf (f, "\n");
  1092.         break;
  1093.     }
  1094. }
  1095.  
  1096.  
  1097. void write_material (FILE *f, char *mat)
  1098. {
  1099.     MatProp *mprop = LIST_FIND (mprop_list, mat);
  1100.  
  1101.     if (mprop == NULL)
  1102.        mprop = &DefaultMaterial;
  1103.  
  1104.     switch (format) {
  1105.     case POV10:
  1106.         write_pov10_material (f, mprop);
  1107.         break;
  1108.  
  1109.     case POV20:
  1110.         write_pov20_material (f, mprop);
  1111.         break;
  1112.  
  1113.     case VIVID:
  1114.         write_vivid_material (f, mprop);
  1115.         break;
  1116.  
  1117.     case POLYRAY:
  1118.         write_polyray_material (f, mprop);
  1119.         break;
  1120.     }
  1121. }
  1122.  
  1123.  
  1124. void write_pov10_material (FILE *f, MatProp *m)
  1125. {
  1126.     float amb = 0.1, dif = 0.9, spec = 1.0;
  1127.     float dist_white, dist_diff, phong, phong_size;
  1128.     float red, green, blue;
  1129.  
  1130.     /* amb = get_ambient (m); */
  1131.  
  1132.     if (m->self_illum) {
  1133.     amb = 0.9;
  1134.     dif = 0.1;
  1135.     }
  1136.  
  1137.     dist_white = fabs(1.0 - m->specular.red) +
  1138.          fabs(1.0 - m->specular.green) +
  1139.          fabs(1.0 - m->specular.blue);
  1140.  
  1141.     dist_diff  = fabs(m->diffuse.red   - m->specular.red) +
  1142.          fabs(m->diffuse.green - m->specular.green) +
  1143.          fabs(m->diffuse.blue  - m->specular.blue);
  1144.  
  1145.  
  1146.     phong_size = 0.7*m->shininess;
  1147.     if (phong_size < 1.0) phong_size = 1.0;
  1148.  
  1149.     if (phong_size > 30.0)
  1150.     phong = 1.0;
  1151.     else
  1152.     phong = phong_size/30.0;
  1153.  
  1154.     fprintf (f, "#declare %s = texture {\n", m->name);
  1155.     fprintf (f, "    ambient %.2f\n", amb);
  1156.     fprintf (f, "    diffuse %.2f\n", dif);
  1157.     fprintf (f, "    phong %.2f\n", phong);
  1158.     fprintf (f, "    phong_size %.1f\n", phong_size);
  1159.  
  1160.     if (dist_diff < dist_white)
  1161.     fprintf (f, "    metallic\n");
  1162.  
  1163.     if (m->reflection > 0.0) {
  1164.     spec = (m->specular.red + m->specular.green + m->specular.blue)/3.0;
  1165.     fprintf (f, "    reflection %.3f\n", spec * m->reflection);
  1166.     }
  1167.  
  1168.     if (m->transparency > 0.0) {
  1169.     red   = m->diffuse.red;
  1170.     green = m->diffuse.green;
  1171.     blue  = m->diffuse.blue;
  1172.  
  1173.     /* Saturate the colour towards white as the transparency increases */
  1174.     red   = ((1.0 - m->transparency) * red)   + m->transparency;
  1175.     green = ((1.0 - m->transparency) * green) + m->transparency;
  1176.     blue  = ((1.0 - m->transparency) * blue)  + m->transparency;
  1177.  
  1178.     fprintf (f, "    color red %.3f green %.3f blue %.3f alpha %.3f\n",
  1179.              red, green, blue, m->transparency);
  1180.     fprintf (f, "    ior 1.1\n");
  1181.     fprintf (f, "    refraction 1.0\n");
  1182.     }
  1183.     else
  1184.     fprintf (f, "    color red %.3f green %.3f blue %.3f\n",
  1185.              m->diffuse.red, m->diffuse.green, m->diffuse.blue);
  1186.  
  1187.     if (strlen (m->tex_map) > 0) {
  1188.     fprintf (f, "    /* Image map: %s, Strength: %.2f */\n",
  1189.              m->tex_map, m->tex_strength);
  1190.     }
  1191.  
  1192.     if (strlen (m->bump_map) > 0) {
  1193.     fprintf (f, "    /* Bump map: %s, Strength: %.2f */\n",
  1194.              m->bump_map, m->bump_strength);
  1195.     }
  1196.  
  1197.     fprintf (f, "}\n\n");
  1198. }
  1199.  
  1200.  
  1201. void write_pov20_material (FILE *f, MatProp *m)
  1202. {
  1203.     float amb = 0.1, dif = 0.9, spec = 1.0;
  1204.     float dist_white, dist_diff, phong, phong_size;
  1205.     float red, green, blue;
  1206.  
  1207.     /* amb = get_ambient (m); */
  1208.  
  1209.     if (m->self_illum) {
  1210.     amb = 0.9;
  1211.     dif = 0.1;
  1212.     }
  1213.  
  1214.     dist_white = fabs(1.0 - m->specular.red) +
  1215.          fabs(1.0 - m->specular.green) +
  1216.          fabs(1.0 - m->specular.blue);
  1217.  
  1218.     dist_diff  = fabs(m->diffuse.red   - m->specular.red) +
  1219.          fabs(m->diffuse.green - m->specular.green) +
  1220.          fabs(m->diffuse.blue  - m->specular.blue);
  1221.  
  1222.     phong_size = 0.7*m->shininess;
  1223.     if (phong_size < 1.0) phong_size = 1.0;
  1224.  
  1225.     if (phong_size > 30.0)
  1226.     phong = 1.0;
  1227.     else
  1228.     phong = phong_size/30.0;
  1229.  
  1230.     fprintf (f, "#declare %s = texture {\n", m->name);
  1231.     fprintf (f, "    finish {\n");
  1232.     fprintf (f, "        ambient %.2f\n", amb);
  1233.     fprintf (f, "        diffuse %.2f\n", dif);
  1234.     fprintf (f, "        phong %.2f\n", phong);
  1235.     fprintf (f, "        phong_size %.1f\n", phong_size);
  1236.  
  1237.     if (dist_diff < dist_white)
  1238.     fprintf (f, "        metallic\n");
  1239.  
  1240.     if (m->reflection > 0.0) {
  1241.     spec = (m->specular.red + m->specular.green + m->specular.blue)/3.0;
  1242.     fprintf (f, "        reflection %.3f\n", spec * m->reflection);
  1243.     }
  1244.  
  1245.     if (m->transparency > 0.0) {
  1246.     fprintf (f, "        ior 1.1\n");
  1247.     fprintf (f, "        refraction 1.0\n");
  1248.     }
  1249.  
  1250.     fprintf (f, "    }\n");
  1251.  
  1252.     if (m->transparency > 0.0) {
  1253.     red   = m->diffuse.red;
  1254.     green = m->diffuse.green;
  1255.     blue  = m->diffuse.blue;
  1256.  
  1257.     /* Saturate the colour towards white as the transparency increases */
  1258.     red   = ((1.0 - m->transparency) * red)   + m->transparency;
  1259.     green = ((1.0 - m->transparency) * green) + m->transparency;
  1260.     blue  = ((1.0 - m->transparency) * blue)  + m->transparency;
  1261.  
  1262.     fprintf (f, "    pigment { rgbf <%.3f, %.3f, %.3f, %.3f> }\n",
  1263.             red, green, blue, m->transparency);
  1264.     }
  1265.     else
  1266.     fprintf (f, "    pigment { rgb <%.3f, %.3f, %.3f> }\n",
  1267.             m->diffuse.red, m->diffuse.green, m->diffuse.blue);
  1268.  
  1269.     if (strlen (m->tex_map) > 0) {
  1270.     fprintf (f, "    /* Image map: %s, Strength: %.2f */\n",
  1271.              m->tex_map, m->tex_strength);
  1272.     }
  1273.  
  1274.     if (strlen (m->bump_map) > 0) {
  1275.     fprintf (f, "    /* Bump map: %s, Strength: %.2f */\n",
  1276.              m->bump_map, m->bump_strength);
  1277.     }
  1278.  
  1279.     fprintf (f, "}\n\n");
  1280. }
  1281.  
  1282.  
  1283. void write_vivid_material (FILE *f, MatProp *m)
  1284. {
  1285.     float amb = 0.1, dif = 0.9;
  1286.  
  1287.     /* amb = get_ambient (m); */
  1288.  
  1289.     if (m->self_illum) {
  1290.     amb = 0.9;
  1291.     dif = 0.1;
  1292.     }
  1293.  
  1294.     if (m->transparency > 0.0) {
  1295.        dif = dif - m->transparency;
  1296.        if (dif < 0.0) dif = 0.0;
  1297.     }
  1298.  
  1299.     fprintf (f, "#define %s \\ \n", m->name);
  1300.     fprintf (f, "    surface {           \\ \n");
  1301.     fprintf (f, "        ambient %.3f %.3f %.3f \\ \n",
  1302.              amb*m->ambient.red, amb*m->ambient.green, amb*m->ambient.blue);
  1303.  
  1304.     fprintf (f, "        diffuse %.3f %.3f %.3f \\ \n",
  1305.              dif*m->diffuse.red, dif*m->diffuse.green, dif*m->diffuse.blue);
  1306.  
  1307.     fprintf (f, "        shine %.1f  %.3f %.3f %.3f \\ \n",
  1308.              0.7*m->shininess, m->specular.red, m->specular.green, m->specular.blue);
  1309.  
  1310.     if (m->transparency > 0.0) {
  1311.     fprintf (f, "        transparent %.3f*white \\ \n", 1.0 - (1.0 - m->transparency)/14.0);
  1312.     fprintf (f, "        ior 1.1 \\ \n");
  1313.     }
  1314.  
  1315.     if (m->reflection > 0.0)
  1316.     fprintf (f, "        specular %.3f*white \\ \n", m->reflection);
  1317.  
  1318.     if (strlen (m->tex_map) > 0) {
  1319.     fprintf (f, "        /* Image map: %s, Strength: %.2f */ \\ \n",
  1320.                  m->tex_map, m->tex_strength);
  1321.     }
  1322.  
  1323.     if (strlen (m->bump_map) > 0) {
  1324.     fprintf (f, "        /* Bump map: %s, Strength: %.2f */ \\ \n",
  1325.                  m->bump_map, m->bump_strength);
  1326.     }
  1327.  
  1328.     fprintf (f, "    }\n\n");
  1329. }
  1330.  
  1331.  
  1332. void write_polyray_material (FILE *f, MatProp *m)
  1333. {
  1334.     float amb = 0.1, dif = 0.9, spec;
  1335.  
  1336.     /* amb = get_ambient (m); */
  1337.  
  1338.     if (m->self_illum) {
  1339.     amb = 0.9;
  1340.     dif = 0.1;
  1341.     }
  1342.  
  1343.     if (m->transparency > 0.0) {
  1344.        dif = dif - m->transparency;
  1345.        if (dif < 0.0) dif = 0.0;
  1346.     }
  1347.  
  1348.     if (m->shininess == 0.0)
  1349.     m->shininess = 0.1;
  1350.  
  1351.     if (m->shininess > 40.0)
  1352.     spec = 1.0;
  1353.     else
  1354.     spec = m->shininess/40.0;
  1355.  
  1356.     fprintf (f, "define %s\n", m->name);
  1357.     fprintf (f, "texture {\n");
  1358.     fprintf (f, "    surface {\n");
  1359.     fprintf (f, "        ambient <%.3f, %.3f, %.3f>, %.1f\n",
  1360.              m->ambient.red, m->ambient.green, m->ambient.blue, amb);
  1361.  
  1362.     fprintf (f, "        diffuse <%.3f, %.3f, %.3f>, %.1f\n",
  1363.              m->diffuse.red, m->diffuse.green, m->diffuse.blue, dif);
  1364.  
  1365.     fprintf (f, "        specular <%.3f, %.3f, %.3f>, %.2f\n",
  1366.              m->specular.red, m->specular.green, m->specular.blue, spec);
  1367.  
  1368.     fprintf (f, "        microfacet Reitz %.1f\n", 400.0/m->shininess);
  1369.  
  1370.     if (m->transparency > 0.0)
  1371.     fprintf (f, "        transmission %.3f, 1.1\n", m->transparency);
  1372.  
  1373.     if (m->reflection > 0.0)
  1374.     fprintf (f, "        reflection %.3f\n", m->reflection);
  1375.  
  1376.     if (strlen (m->tex_map) > 0) {
  1377.     fprintf (f, "        // Image map: %s, Strength: %.2f\n",
  1378.                  m->tex_map, m->tex_strength);
  1379.     }
  1380.  
  1381.     if (strlen (m->bump_map) > 0) {
  1382.     fprintf (f, "        // Bump map: %s, Strength: %.2f\n",
  1383.                  m->bump_map, m->bump_strength);
  1384.     }
  1385.  
  1386.     fprintf (f, "    }\n");
  1387.     fprintf (f, "}\n\n");
  1388. }
  1389.  
  1390.  
  1391. /* Write a mesh file */
  1392. void write_mesh (FILE *f, Mesh *mesh)
  1393. {
  1394.     int i;
  1395.     Vector va, vb, vc;
  1396.     Summary *new_summary;
  1397.     Matrix obj_matrix;
  1398.  
  1399.     if (mesh->hidden || LIST_FIND (excl_list, mesh->name))
  1400.     return;
  1401.  
  1402.     /* Add this object's stats to the summary */
  1403.     new_summary = malloc (sizeof(*new_summary));
  1404.     if (new_summary == NULL)
  1405.     abortmsg ("Out of memory adding summary", 1);
  1406.  
  1407.     strcpy (new_summary->name, mesh->name);
  1408.     vect_copy (new_summary->center,  mesh->center);
  1409.     vect_copy (new_summary->lengths, mesh->lengths);
  1410.  
  1411.     LIST_INSERT (summary, new_summary);
  1412.  
  1413.     /* Compute the object transformation matrix for animations */
  1414.     if (ani_matrix != NULL) {
  1415.     mat_copy (obj_matrix, *ani_matrix);
  1416.     if (vue_version > 2.0)
  1417.         mat_mult (obj_matrix, mesh->invmatrix, obj_matrix);
  1418.     }
  1419.  
  1420.     switch (format) {
  1421.     case POV10:
  1422.     case POV20:
  1423.     case VIVID:
  1424.     case POLYRAY:
  1425.         opt_set_vert (mesh->vertices);
  1426.  
  1427.         for (i = 0; i < mesh->faces; i++) {
  1428.         vect_copy (va, mesh->vertex[mesh->face[i].a]);
  1429.         vect_copy (vb, mesh->vertex[mesh->face[i].b]);
  1430.         vect_copy (vc, mesh->vertex[mesh->face[i].c]);
  1431.  
  1432.         opt_set_texture (mesh->mtl[i]->name);
  1433.  
  1434.         opt_add_tri (va[X], va[Y], va[Z], vc[X], vc[Y], vc[Z],
  1435.                  vb[X], vb[Y], vb[Z]);
  1436.         }
  1437.  
  1438.         fclose (f);
  1439.  
  1440.         if (ani_matrix != NULL)
  1441.         opt_set_transform (obj_matrix);
  1442.  
  1443.         if (box_all || LIST_FIND (box_list, mesh->name))
  1444.         opt_write_box (mesh->name);
  1445.         else
  1446.         opt_write_file (mesh->name);
  1447.  
  1448.         f = fopen (outname, "a");
  1449.         break;
  1450.  
  1451.     case RAW:
  1452.         fprintf (f, "%s\n", mesh->name);
  1453.  
  1454.         for (i = 0; i < mesh->faces; i++) {
  1455.         vect_copy (va, mesh->vertex[mesh->face[i].a]);
  1456.         vect_copy (vb, mesh->vertex[mesh->face[i].b]);
  1457.         vect_copy (vc, mesh->vertex[mesh->face[i].c]);
  1458.  
  1459.         if (ani_matrix != NULL) {
  1460.             vect_transform (va, va, obj_matrix);
  1461.             vect_transform (vb, vb, obj_matrix);
  1462.             vect_transform (vc, vc, obj_matrix);
  1463.         }
  1464.  
  1465.         fprintf (f, "%f %f %f   %f %f %f   %f %f %f\n",
  1466.                 va[X], va[Y], va[Z], vb[X], vb[Y], vb[Z],
  1467.                 vc[X], vc[Y], vc[Z]);
  1468.         }
  1469.  
  1470.         break;
  1471.     }
  1472. }
  1473.  
  1474.  
  1475. /* Parses an object transformation and returns a pointer to the
  1476.    newly allocated transformation */
  1477. Transform *parse_transform (char *string)
  1478. {
  1479.     Transform *t;
  1480.     char      *token;
  1481.     int       token_no;
  1482.  
  1483.     t = (Transform *)malloc (sizeof(*t));
  1484.     if (t == NULL)
  1485.     abortmsg ("Out of memory allocating transform", 1);
  1486.  
  1487.     mat_identity (t->matrix);
  1488.  
  1489.     token = parse_string (string);
  1490.     token_no = 0;
  1491.  
  1492.     while (strlen(token) > 0) {
  1493.      switch (token_no) {
  1494.          case  0: break;
  1495.          case  1: strcpy (t->name, token); break;
  1496.          case  2: t->matrix[0][0] = atof(token); break;
  1497.          case  3: t->matrix[0][1] = atof(token); break;
  1498.          case  4: t->matrix[0][2] = atof(token); break;
  1499.          case  5: t->matrix[1][0] = atof(token); break;
  1500.          case  6: t->matrix[1][1] = atof(token); break;
  1501.          case  7: t->matrix[1][2] = atof(token); break;
  1502.          case  8: t->matrix[2][0] = atof(token); break;
  1503.          case  9: t->matrix[2][1] = atof(token); break;
  1504.          case 10: t->matrix[2][2] = atof(token); break;
  1505.          case 11: t->matrix[3][0] = atof(token); break;
  1506.          case 12: t->matrix[3][1] = atof(token); break;
  1507.          case 13: t->matrix[3][2] = atof(token); break;
  1508.  
  1509.          default: abortmsg ("Error parsing transform", 1);
  1510.      }
  1511.  
  1512.      token = parse_string (NULL);
  1513.      token_no++;
  1514.     }
  1515.  
  1516.     t->matrix[0][3] = 0.0;
  1517.     t->matrix[1][3] = 0.0;
  1518.     t->matrix[2][3] = 0.0;
  1519.     t->matrix[3][3] = 1.0;
  1520.  
  1521.     cleanup_name (t->name);
  1522.  
  1523.     return t;
  1524. }
  1525.  
  1526.  
  1527. /* Parses a morph command and returns a pointer to the
  1528.    newly allocated morph */
  1529. Morph *parse_morph (char *string)
  1530. {
  1531.     Morph  *m;
  1532.     char   *token;
  1533.     int    i, token_no;
  1534.  
  1535.     m = (Morph *)malloc (sizeof(*m));
  1536.     if (m == NULL)
  1537.     abortmsg ("Out of memory allocating morph", 1);
  1538.  
  1539.     mat_identity (m->matrix);
  1540.  
  1541.     token = parse_string (string);
  1542.  
  1543.     token = parse_string (NULL);
  1544.     strcpy (m->name, token);
  1545.  
  1546.     token = parse_string (NULL);
  1547.     m->count = atoi (token);
  1548.  
  1549.     if (strlen (m->name) == 0 || m->count < 1 || m->count > 4)
  1550.     abortmsg ("Error parsing morph command", 1);
  1551.  
  1552.     cleanup_name (m->name);
  1553.  
  1554.     for (i = 0; i < m->count; i++) {
  1555.     token = parse_string (NULL);
  1556.     strcpy (m->names[i], token);
  1557.  
  1558.     token = parse_string (NULL);
  1559.     m->weight[i] = atof (token);
  1560.  
  1561.     if (strlen (m->names[i]) == 0)
  1562.         abortmsg ("Error parsing morph command", 1);
  1563.  
  1564.     cleanup_name (m->names[i]);
  1565.     }
  1566.  
  1567.     token = parse_string (NULL);
  1568.     token_no = 0;
  1569.  
  1570.     while (strlen(token) > 0) {
  1571.      switch (token_no) {
  1572.          case  0: m->matrix[0][0] = atof(token); break;
  1573.          case  1: m->matrix[0][1] = atof(token); break;
  1574.          case  2: m->matrix[0][2] = atof(token); break;
  1575.          case  3: m->matrix[1][0] = atof(token); break;
  1576.          case  4: m->matrix[1][1] = atof(token); break;
  1577.          case  5: m->matrix[1][2] = atof(token); break;
  1578.          case  6: m->matrix[2][0] = atof(token); break;
  1579.          case  7: m->matrix[2][1] = atof(token); break;
  1580.          case  8: m->matrix[2][2] = atof(token); break;
  1581.          case  9: m->matrix[3][0] = atof(token); break;
  1582.          case 10: m->matrix[3][1] = atof(token); break;
  1583.          case 11: m->matrix[3][2] = atof(token); break;
  1584.  
  1585.          default: abortmsg ("Error parsing morph command", 1);
  1586.      }
  1587.  
  1588.      token = parse_string (NULL);
  1589.      token_no++;
  1590.     }
  1591.  
  1592.     m->matrix[0][3] = 0.0;
  1593.     m->matrix[1][3] = 0.0;
  1594.     m->matrix[2][3] = 0.0;
  1595.     m->matrix[3][3] = 1.0;
  1596.  
  1597.     return m;
  1598. }
  1599.  
  1600.  
  1601. /* Parses an omni light and returns a pointer to the
  1602.    newly allocated light */
  1603. OmniLight *parse_omnilight (char *string)
  1604. {
  1605.     OmniLight *o;
  1606.     char      *token;
  1607.     int       token_no;
  1608.  
  1609.     o = (OmniLight *)malloc (sizeof(*o));
  1610.     if (o == NULL)
  1611.     abortmsg ("Out of memory allocating omnilight", 1);
  1612.  
  1613.     token = parse_string (string);
  1614.     token_no = 0;
  1615.  
  1616.     while (strlen(token) > 0) {
  1617.      switch (token_no) {
  1618.          case 0: break;
  1619.          case 1: strcpy (o->name, token); break;
  1620.          case 2: o->pos[X] = atof (token); break;
  1621.          case 3: o->pos[Y] = atof (token); break;
  1622.          case 4: o->pos[Z] = atof (token); break;
  1623.          case 5: o->col.red   = atof (token); break;
  1624.          case 6: o->col.green = atof (token); break;
  1625.          case 7: o->col.blue  = atof (token); break;
  1626.  
  1627.          default: abortmsg ("Error parsing omnilight", 1);
  1628.      }
  1629.  
  1630.      token = parse_string (NULL);
  1631.      token_no++;
  1632.     }
  1633.  
  1634.     cleanup_name (o->name);
  1635.  
  1636.     return o;
  1637. }
  1638.  
  1639.  
  1640. /* Parses a spotlight and returns a pointer to the
  1641.    newly allocated spotlight */
  1642. Spotlight *parse_spotlight (char *string)
  1643. {
  1644.     Spotlight *s;
  1645.     char      *token;
  1646.     int       token_no;
  1647.  
  1648.     s = (Spotlight *)malloc (sizeof(*s));
  1649.     if (s == NULL)
  1650.     abortmsg ("Out of memory allocating spotlight", 1);
  1651.  
  1652.     token = parse_string (string);
  1653.     token_no = 0;
  1654.  
  1655.     while (strlen(token) > 0) {
  1656.      switch (token_no) {
  1657.          case  0: break;
  1658.          case  1: strcpy (s->name, token); break;
  1659.          case  2: s->pos[X] = atof (token); break;
  1660.          case  3: s->pos[Y] = atof (token); break;
  1661.          case  4: s->pos[Z] = atof (token); break;
  1662.          case  5: s->target[X] = atof (token); break;
  1663.          case  6: s->target[Y] = atof (token); break;
  1664.          case  7: s->target[Z] = atof (token); break;
  1665.          case  8: s->col.red   = atof (token); break;
  1666.          case  9: s->col.green = atof (token); break;
  1667.          case 10: s->col.blue  = atof (token); break;
  1668.          case 11: s->hotspot   = atof (token); break;
  1669.          case 12: s->falloff   = atof (token); break;
  1670.          case 13: break;
  1671.  
  1672.          default: abortmsg ("Error parsing spotlight", 1);
  1673.      }
  1674.  
  1675.      token = parse_string (NULL);
  1676.      token_no++;
  1677.     }
  1678.  
  1679.     cleanup_name (s->name);
  1680.  
  1681.     return s;
  1682. }
  1683.  
  1684.  
  1685. /* Parses a camera command and returns a pointer to the
  1686.    newly allocated camera */
  1687. Camera *parse_camera (char *string)
  1688. {
  1689.     Camera *c;
  1690.     char   *token;
  1691.     int    token_no;
  1692.  
  1693.     c = (Camera *)malloc (sizeof(*c));
  1694.     if (c == NULL)
  1695.     abortmsg ("Out of memory allocating camera", 1);
  1696.  
  1697.     token = parse_string (string);
  1698.     token_no = 0;
  1699.  
  1700.     while (strlen(token) > 0) {
  1701.      switch (token_no) {
  1702.          case 0: break;
  1703.          case 1: c->pos[X] = atof (token); break;
  1704.          case 2: c->pos[Y] = atof (token); break;
  1705.          case 3: c->pos[Z] = atof (token); break;
  1706.          case 4: c->target[X] = atof (token); break;
  1707.          case 5: c->target[Y] = atof (token); break;
  1708.          case 6: c->target[Z] = atof (token); break;
  1709.          case 7: c->bank = atof (token); break;
  1710.          case 8: c->lens = atof (token); break;
  1711.  
  1712.          default: abortmsg ("Error parsing camera", 1);
  1713.      }
  1714.  
  1715.      token = parse_string (NULL);
  1716.      token_no++;
  1717.     }
  1718.  
  1719.     return c;
  1720. }
  1721.  
  1722.  
  1723. /* Load the transforms, camera movements, etc for the specified frame */
  1724. void read_frame (char *filename, int frame_no)
  1725. {
  1726.     FILE  *f;
  1727.     char  fname[80];
  1728.     char  string[256];
  1729.     char  *token;
  1730.  
  1731.     /* Open the .vue file */
  1732.     strcpy (fname, filename);   /* Make a copy we can mess with */
  1733.     add_ext (fname, "vue", 0);
  1734.  
  1735.     f = fopen (fname, "r");
  1736.     if (f == NULL) {
  1737.     printf ("Error opening file '%s'\n", fname);
  1738.     exit(1);
  1739.     }
  1740.  
  1741.     /* Load the specified frame */
  1742.     find_frame (f, frame_no);
  1743.  
  1744.     while (fgets (string, 256, f) != NULL) {
  1745.     token = parse_string (string);
  1746.  
  1747.     if (strcmp (token, "frame") == 0)
  1748.         break;
  1749.     else if (strcmp (token, "transform") == 0) {
  1750.         LIST_INSERT (trans_list, parse_transform (string));
  1751.     }
  1752.     else if (strcmp (token, "morph") == 0) {
  1753.         LIST_INSERT (morph_list, parse_morph (string));
  1754.     }
  1755.     else if (strcmp (token, "light") == 0) {
  1756.         LIST_INSERT (omni_list, parse_omnilight (string));
  1757.     }
  1758.     else if (strcmp (token, "spotlight") == 0) {
  1759.         LIST_INSERT (spot_list, parse_spotlight (string));
  1760.     }
  1761.     else if (strcmp (token, "camera") == 0) {
  1762.         if (cam_list != NULL)
  1763.         abortmsg ("ERROR - Multiple cameras in .vue file", 1);
  1764.  
  1765.         LIST_INSERT (cam_list, parse_camera (string));
  1766.     }
  1767.     else if (strcmp (token, "top") == 0)
  1768.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1769.     else if (strcmp (token, "bottom") == 0)
  1770.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1771.     else if (strcmp (token, "left") == 0)
  1772.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1773.     else if (strcmp (token, "right") == 0)
  1774.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1775.     else if (strcmp (token, "front") == 0)
  1776.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1777.     else if (strcmp (token, "back") == 0)
  1778.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1779.     else if (strcmp (token, "user") == 0)
  1780.         abortmsg ("ERROR - User viewports are not supported", 1);
  1781.     }
  1782.  
  1783.     fclose(f);
  1784. }
  1785.  
  1786.  
  1787. void find_frame (FILE *f, int frame_no)
  1788. {
  1789.     char  string[256];
  1790.     char  *token;
  1791.     int   frame = 0;
  1792.  
  1793.     /* Search the .vue file for the required frame */
  1794.     while (1) {
  1795.     /* Read the next line in the file */
  1796.     if (fgets (string, 256, f) == NULL) {
  1797.         printf ("Unable to locate frame #%d in .vue file\n", frame_no);
  1798.         exit(1);
  1799.     }
  1800.  
  1801.     token = parse_string (string);
  1802.  
  1803.     if (strcmp (token, "frame") == 0) {
  1804.         token = parse_string (NULL);
  1805.  
  1806.         if (strlen(token) == 0) {
  1807.         printf ("Unable to locate frame #%d in .vue file\n", frame_no);
  1808.         exit(1);
  1809.         }
  1810.  
  1811.         frame = atoi (token);
  1812.  
  1813.         if (frame == frame_no)
  1814.         break;
  1815.     }
  1816.     else if (strcmp (token, "VERSION") == 0) {
  1817.         token = parse_string (NULL);
  1818.  
  1819.         vue_version = atoi(token) / 100.0;
  1820.     }
  1821.     }
  1822. }
  1823.  
  1824.  
  1825. void save_animation()
  1826. {
  1827.     Mesh      *mesh, *master;
  1828.     Transform *t;
  1829.     Morph     *m;
  1830.     Vector    temp;
  1831.     int       i, j;
  1832.  
  1833.     printf ("\n");
  1834.  
  1835.     for (t = trans_list; t != NULL; t = t->next) {
  1836.      printf ("Transforming object: %s\n", t->name);
  1837.  
  1838.      ani_matrix = &(t->matrix);
  1839.  
  1840.      mesh = LIST_FIND (mesh_list, t->name);
  1841.  
  1842.      if (mesh == NULL) {
  1843.          printf ("Unable to locate mesh object %s\n", t->name);
  1844.          exit(1);
  1845.      }
  1846.  
  1847.      write_mesh (out, mesh);
  1848.     }
  1849.  
  1850.     for (m = morph_list; m != NULL; m = m->next) {
  1851.     printf ("Morphing object: %s\n", m->name);
  1852.  
  1853.     ani_matrix = &(m->matrix);
  1854.  
  1855.     mesh = LIST_FIND (mesh_list, m->name);
  1856.     if (mesh == NULL) {
  1857.         printf ("Unable to locate mesh object %s\n", m->name);
  1858.         exit(1);
  1859.     }
  1860.  
  1861.     /* Make a copy to mess with */
  1862.     master = copy_mesh (mesh);
  1863.     master->hidden = FALSE;
  1864.  
  1865.     strcpy (master->name, m->name);
  1866.  
  1867.     for (i = 0; i < master->vertices; i++)
  1868.         vect_init (master->vertex[i], 0.0, 0.0, 0.0);
  1869.  
  1870.     for (i = 0; i < m->count; i++) {
  1871.         mesh = LIST_FIND (mesh_list, m->names[i]);
  1872.         if (mesh == NULL) {
  1873.         printf ("Unable to locate mesh object %s\n", m->names[0]);
  1874.         exit(1);
  1875.         }
  1876.  
  1877.         if (mesh->vertices != master->vertices)
  1878.         abortmsg ("Morphed objects do not contain the same number of vertices", 1);
  1879.  
  1880.         if (mesh->faces != master->faces)
  1881.         abortmsg ("Morphed objects do not contain the same number of faces", 1);
  1882.  
  1883.         for (j = 0; j < master->vertices; j++) {
  1884.         vect_transform (temp, mesh->vertex[j], mesh->invmatrix);
  1885.         vect_scale (temp, temp, m->weight[i]);
  1886.         vect_add (master->vertex[j], master->vertex[j], temp);
  1887.         }
  1888.     }
  1889.  
  1890.     for (i = 0; i < master->vertices; i++)
  1891.         vect_transform (master->vertex[i], master->vertex[i], master->matrix);
  1892.  
  1893.     write_mesh (out, master);
  1894.  
  1895.     free_mesh_data (master);
  1896.     free (master);
  1897.     }
  1898.  
  1899.     for (mesh = mesh_list; mesh != NULL; mesh = mesh->next)
  1900.     free_mesh_data (mesh);
  1901. }
  1902.  
  1903.  
  1904. /* Create a new mesh */
  1905. Mesh *create_mesh (char *name, int vertices, int faces)
  1906. {
  1907.     Mesh *new_mesh;
  1908.  
  1909.     new_mesh = malloc (sizeof(*new_mesh));
  1910.     if (new_mesh == NULL)
  1911.     abortmsg ("Out of memory allocating mesh", 1);
  1912.  
  1913.     strcpy (new_mesh->name, name);
  1914.  
  1915.     new_mesh->vertices = vertices;
  1916.  
  1917.     if (vertices <= 0)
  1918.     new_mesh->vertex = NULL;
  1919.     else {
  1920.     new_mesh->vertex = malloc (vertices * sizeof(*new_mesh->vertex));
  1921.     if (new_mesh->vertex == NULL)
  1922.         abortmsg ("Out of memory allocating mesh", 1);
  1923.     }
  1924.  
  1925.     new_mesh->faces = faces;
  1926.  
  1927.     if (faces <= 0) {
  1928.     new_mesh->face = NULL;
  1929.     new_mesh->mtl = NULL;
  1930.     }
  1931.     else {
  1932.     new_mesh->face = malloc (faces * sizeof(*new_mesh->face));
  1933.     if (new_mesh->face == NULL)
  1934.         abortmsg ("Out of memory allocating mesh", 1);
  1935.  
  1936.     new_mesh->mtl = malloc (faces * sizeof(*new_mesh->mtl));
  1937.     if (new_mesh->mtl == NULL)
  1938.         abortmsg ("Out of memory allocating mesh", 1);
  1939.     }
  1940.  
  1941.     vect_init (new_mesh->center,  0.0, 0.0, 0.0);
  1942.     vect_init (new_mesh->lengths, 0.0, 0.0, 0.0);
  1943.  
  1944.     mat_identity (new_mesh->matrix);
  1945.     mat_identity (new_mesh->invmatrix);
  1946.  
  1947.     new_mesh->hidden = FALSE;
  1948.     new_mesh->shadow = TRUE;
  1949.  
  1950.     return new_mesh;
  1951. }
  1952.  
  1953.  
  1954. /* Creates a duplicate copy of a mesh */
  1955. Mesh *copy_mesh (Mesh *mesh)
  1956. {
  1957.     Mesh *new_mesh;
  1958.     int  i;
  1959.  
  1960.     new_mesh = create_mesh (mesh->name, mesh->vertices, mesh->faces);
  1961.  
  1962.     if (new_mesh == NULL)
  1963.     abortmsg ("Out of memory allocating mesh", 1);
  1964.  
  1965.     for (i = 0; i < mesh->vertices; i++)
  1966.     vect_copy (new_mesh->vertex[i], mesh->vertex[i]);
  1967.  
  1968.     for (i = 0; i < mesh->faces; i++) {
  1969.     new_mesh->face[i] = mesh->face[i];
  1970.     new_mesh->mtl[i]  = mesh->mtl[i];
  1971.     }
  1972.  
  1973.     mat_copy (new_mesh->matrix, mesh->matrix);
  1974.     mat_copy (new_mesh->invmatrix, mesh->invmatrix);
  1975.  
  1976.     vect_copy (new_mesh->center,  mesh->center);
  1977.     vect_copy (new_mesh->lengths, mesh->lengths);
  1978.  
  1979.     new_mesh->hidden = mesh->hidden;
  1980.     new_mesh->shadow = mesh->shadow;
  1981.  
  1982.     return new_mesh;
  1983. }
  1984.  
  1985.  
  1986. /* Free all data associated with mesh object */
  1987. void free_mesh_data (Mesh *mesh)
  1988. {
  1989.     if (mesh->vertex != NULL)
  1990.     free (mesh->vertex);
  1991.  
  1992.     if (mesh->face != NULL)
  1993.     free (mesh->face);
  1994.  
  1995.     if (mesh->mtl != NULL)
  1996.     free (mesh->mtl);
  1997. }
  1998.  
  1999.  
  2000. /* Updates the center (pivot) point of the mesh */
  2001. void update_limits (Mesh *mesh)
  2002. {
  2003.     Vector vmin = {+MAXFLOAT, +MAXFLOAT, +MAXFLOAT};
  2004.     Vector vmax = {-MAXFLOAT, -MAXFLOAT, -MAXFLOAT};
  2005.     int    i;
  2006.  
  2007.     for (i = 0; i < mesh->vertices; i++) {
  2008.     vect_min (vmin, vmin, mesh->vertex[i]);
  2009.     vect_max (vmax, vmax, mesh->vertex[i]);
  2010.     }
  2011.  
  2012.     vect_add  (mesh->center, vmin, vmax);
  2013.     vect_scale (mesh->center, mesh->center, 0.5);
  2014.  
  2015.     vect_sub (mesh->lengths, vmax, vmin);
  2016. }
  2017.  
  2018.  
  2019. /* Return the sub-string of 'str' that is before 'target' */
  2020. char *before (char *str, char *target)
  2021. {
  2022.     static char result[256];
  2023.     char   *search;
  2024.  
  2025.     strncpy (result, str, 256);
  2026.     result[255] = '\0';
  2027.  
  2028.     search = strstr (result, target);
  2029.  
  2030.     if (search != NULL)
  2031.     *search = '\0';
  2032.  
  2033.     return result;
  2034. }
  2035.  
  2036.  
  2037. /* Return the sub-string of 'str' that is after 'target' */
  2038. char *after (char *str, char *target)
  2039. {
  2040.     static char result[256];
  2041.     char   *search;
  2042.  
  2043.     search = strstr (str, target);
  2044.  
  2045.     if (search == NULL)
  2046.     strncpy (result, "", 256);
  2047.     else
  2048.     strncpy (result, search + strlen(target), 256);
  2049.  
  2050.     result[255] = '\0';
  2051.  
  2052.     return result;
  2053. }
  2054.  
  2055.  
  2056. /* Return the sub-string of 'str' that is between 'target1' and 'target2' */
  2057. char *between (char *str, char *target1, char *target2)
  2058. {
  2059.     static char result[256];
  2060.  
  2061.     strcpy (result, after (str, target1));
  2062.     strcpy (result, before (result, target2));
  2063.  
  2064.     return result;
  2065. }
  2066.  
  2067.  
  2068. /* Works like the C strtok() function except that it can handle */
  2069. /* tokens enclosed in double quotes */
  2070. char *parse_string (char *str)
  2071. {
  2072.     static char result[256];
  2073.     static char *p;
  2074.     char QUOTE = '\"';
  2075.     int  index;
  2076.  
  2077.     strcpy (result, "");
  2078.     index = 0;
  2079.  
  2080.     if (str != NULL)
  2081.     p = str;
  2082.  
  2083.     /* Find the start of the next token */
  2084.     while (isspace (*p))
  2085.     p++;
  2086.  
  2087.     if (*p == QUOTE) {
  2088.     p++;
  2089.  
  2090.     while (*p != '\0' && *p != QUOTE)
  2091.         result[index++] = *p++;
  2092.  
  2093.     if (*p == QUOTE)
  2094.         p++;
  2095.     }
  2096.     else {
  2097.     while (*p != '\0' && !isspace(*p))
  2098.         result[index++] = *p++;
  2099.     }
  2100.  
  2101.     result[index] = '\0';
  2102.  
  2103.     return result;
  2104. }
  2105.  
  2106.  
  2107. /* Convert character 'c' to upper case */
  2108. char upcase (char c)
  2109. {
  2110.     if (c >= 'a' && c <= 'z')
  2111.     c = c - 'a' + 'A';
  2112.  
  2113.     return c;
  2114. }
  2115.  
  2116.  
  2117. float colour_intens (Colour *colour)
  2118. {
  2119.     return sqrt (colour->red   * colour->red +
  2120.          colour->green * colour->green +
  2121.          colour->blue  * colour->blue);
  2122. }
  2123.  
  2124.  
  2125. void parse_file()
  2126. {
  2127.     Chunk chunk;
  2128.  
  2129.     start_chunk(&chunk);
  2130.  
  2131.     if (chunk.tag == 0x4D4D)
  2132.     parse_3ds (&chunk);
  2133.     else
  2134.     abortmsg ("Error: Input file is not .3DS format", 1);
  2135.  
  2136.     end_chunk (&chunk);
  2137. }
  2138.  
  2139.  
  2140. void parse_3ds (Chunk *mainchunk)
  2141. {
  2142.     Chunk chunk;
  2143.  
  2144.     do  {
  2145.     start_chunk (&chunk);
  2146.  
  2147.     if (chunk.end <= mainchunk->end) {
  2148.         switch (chunk.tag) {
  2149.         case 0x3D3D: parse_mdata (&chunk);
  2150.                  break;
  2151.         }
  2152.     }
  2153.  
  2154.     end_chunk (&chunk);
  2155.     } while (chunk.end <= mainchunk->end);
  2156. }
  2157.  
  2158.  
  2159. void parse_mdata (Chunk *mainchunk)
  2160. {
  2161.     Chunk chunk;
  2162.     Colour bgnd_colour;
  2163.  
  2164.     do  {
  2165.     start_chunk (&chunk);
  2166.  
  2167.     if (chunk.end <= mainchunk->end) {
  2168.         switch (chunk.tag) {
  2169.         case 0x2100: parse_colour (&global_amb);
  2170.                  break;
  2171.         case 0x1200: parse_colour (&bgnd_colour);
  2172.                  break;
  2173.         case 0x1201: write_bgsolid (out, bgnd_colour);
  2174.                  break;
  2175.         case 0x2200: parse_fog (&chunk);
  2176.                  break;
  2177.         case 0x2210: parse_fog_bgnd();
  2178.                  break;
  2179.         case 0x2201: write_fog (out, fog_colour, fog_distance);
  2180.                  break;
  2181.         case 0xAFFF: parse_mat_entry (&chunk);
  2182.                  break;
  2183.         case 0x4000: parse_named_object (&chunk);
  2184.                  break;
  2185.         }
  2186.     }
  2187.  
  2188.     end_chunk (&chunk);
  2189.     } while (chunk.end <= mainchunk->end);
  2190. }
  2191.  
  2192.  
  2193. void parse_fog (Chunk *mainchunk)
  2194. {
  2195.     Chunk chunk;
  2196.  
  2197.     (void)read_float();
  2198.     (void)read_float();
  2199.     fog_distance = read_float();
  2200.     (void)read_float();
  2201.  
  2202.     parse_colour (&fog_colour);
  2203.  
  2204.     do  {
  2205.     start_chunk (&chunk);
  2206.  
  2207.     if (chunk.end <= mainchunk->end) {
  2208.         switch (chunk.tag) {
  2209.         case 0x2210: parse_fog_bgnd();
  2210.                  break;
  2211.         }
  2212.     }
  2213.  
  2214.     end_chunk (&chunk);
  2215.     } while (chunk.end <= mainchunk->end);
  2216. }
  2217.  
  2218.  
  2219. void parse_fog_bgnd()
  2220. {
  2221.  
  2222. }
  2223.  
  2224.  
  2225. void parse_mat_entry (Chunk *mainchunk)
  2226. {
  2227.     Chunk chunk;
  2228.     MatProp *mprop;
  2229.  
  2230.     mprop = create_mprop();
  2231.  
  2232.     do  {
  2233.     start_chunk (&chunk);
  2234.  
  2235.     if (chunk.end <= mainchunk->end) {
  2236.         switch (chunk.tag) {
  2237.         case 0xA000: strcpy (mprop->name, read_string());
  2238.                  cleanup_name (mprop->name);
  2239.                  break;
  2240.  
  2241.         case 0xA010: parse_colour (&mprop->ambient);
  2242.                  break;
  2243.  
  2244.         case 0xA020: parse_colour (&mprop->diffuse);
  2245.                  break;
  2246.  
  2247.         case 0xA030: parse_colour (&mprop->specular);
  2248.                  break;
  2249.  
  2250.         case 0xA040: mprop->shininess = 100.0*parse_percentage();
  2251.                  break;
  2252.  
  2253.         case 0xA050: mprop->transparency = parse_percentage();
  2254.                  break;
  2255.  
  2256.         case 0xA080: mprop->self_illum = TRUE;
  2257.                  break;
  2258.  
  2259.         case 0xA220: mprop->reflection = parse_percentage();
  2260.                  (void)parse_mapname (&chunk);
  2261.                  break;
  2262.  
  2263.         case 0xA310: if (mprop->reflection == 0.0)
  2264.                  mprop->reflection = 1.0;
  2265.                  break;
  2266.  
  2267.         case 0xA200: mprop->tex_strength = parse_percentage();
  2268.                  strcpy (mprop->tex_map, parse_mapname (&chunk));
  2269.                  break;
  2270.  
  2271.         case 0xA230: mprop->bump_strength = parse_percentage();
  2272.                  strcpy (mprop->bump_map, parse_mapname (&chunk));
  2273.                  break;
  2274.         }
  2275.     }
  2276.  
  2277.     end_chunk (&chunk);
  2278.     } while (chunk.end <= mainchunk->end);
  2279.  
  2280.     LIST_INSERT (mprop_list, mprop);
  2281. }
  2282.  
  2283.  
  2284. char *parse_mapname (Chunk *mainchunk)
  2285. {
  2286.     static char name[80] = "";
  2287.     Chunk chunk;
  2288.  
  2289.     do  {
  2290.     start_chunk (&chunk);
  2291.  
  2292.     if (chunk.end <= mainchunk->end) {
  2293.         switch (chunk.tag) {
  2294.         case 0xA300: strcpy (name, read_string());
  2295.                  break;
  2296.         }
  2297.     }
  2298.  
  2299.     end_chunk (&chunk);
  2300.     } while (chunk.end <= mainchunk->end);
  2301.  
  2302.     return name;
  2303. }
  2304.  
  2305.  
  2306. void parse_named_object (Chunk *mainchunk)
  2307. {
  2308.     Chunk chunk;
  2309.  
  2310.     strcpy (obj_name, read_string());
  2311.     cleanup_name (obj_name);
  2312.  
  2313.     printf ("Working on: %s\n", obj_name);
  2314.  
  2315.     mesh = NULL;
  2316.  
  2317.     do  {
  2318.     start_chunk (&chunk);
  2319.  
  2320.     if (chunk.end <= mainchunk->end) {
  2321.         switch (chunk.tag) {
  2322.         case 0x4100: parse_n_tri_object (&chunk);
  2323.                  break;
  2324.         case 0x4600: parse_n_direct_light (&chunk);
  2325.                  break;
  2326.         case 0x4700: parse_n_camera();
  2327.                  break;
  2328.         case 0x4010: if (mesh != NULL) mesh->hidden = TRUE;
  2329.                  break;
  2330.         case 0x4012: if (mesh != NULL) mesh->shadow = FALSE;
  2331.                  break;
  2332.         }
  2333.     }
  2334.  
  2335.     end_chunk (&chunk);
  2336.     } while (chunk.end <= mainchunk->end);
  2337.  
  2338.     if (mesh != NULL) {
  2339.     update_limits (mesh);
  2340.  
  2341.     if (frame >= 0)
  2342.         LIST_INSERT (mesh_list, mesh);
  2343.     else {
  2344.         write_mesh (out, mesh);
  2345.  
  2346.         free_mesh_data (mesh);
  2347.         free (mesh);
  2348.     }
  2349.     }
  2350. }
  2351.  
  2352.  
  2353. void parse_n_tri_object (Chunk *mainchunk)
  2354. {
  2355.     Chunk chunk;
  2356.  
  2357.     mesh = create_mesh (obj_name, 0, 0);
  2358.  
  2359.     do  {
  2360.     start_chunk (&chunk);
  2361.  
  2362.     if (chunk.end <= mainchunk->end) {
  2363.         switch (chunk.tag) {
  2364.         case 0x4110: parse_point_array();
  2365.                  break;
  2366.         case 0x4120: parse_face_array (&chunk);
  2367.                  break;
  2368.         case 0x4160: parse_mesh_matrix();
  2369.                  break;
  2370.         }
  2371.     }
  2372.  
  2373.     end_chunk (&chunk);
  2374.     } while (chunk.end <= mainchunk->end);
  2375. }
  2376.  
  2377.  
  2378. void parse_point_array()
  2379. {
  2380.     int i;
  2381.  
  2382.     mesh->vertices = read_word();
  2383.     mesh->vertex = malloc (mesh->vertices * sizeof(*(mesh->vertex)));
  2384.     if (mesh->vertex == NULL)
  2385.     abortmsg ("Out of memory allocating mesh", 1);
  2386.  
  2387.     for (i = 0; i < mesh->vertices; i++)
  2388.     read_point (mesh->vertex[i]);
  2389. }
  2390.  
  2391.  
  2392. void parse_face_array (Chunk *mainchunk)
  2393. {
  2394.     Chunk chunk;
  2395.     int i;
  2396.  
  2397.     mesh->faces = read_word();
  2398.     mesh->face = malloc (mesh->faces * sizeof(*(mesh->face)));
  2399.     if (mesh->face == NULL)
  2400.     abortmsg ("Out of memory allocating mesh", 1);
  2401.  
  2402.     mesh->mtl = malloc (mesh->faces * sizeof(*(mesh->mtl)));
  2403.     if (mesh->mtl == NULL)
  2404.     abortmsg ("Out of memory allocating mesh", 1);
  2405.  
  2406.     for (i = 0; i < mesh->faces; i++) {
  2407.     mesh->face[i].a = read_word();
  2408.     mesh->face[i].b = read_word();
  2409.     mesh->face[i].c = read_word();
  2410.     (void)read_word();
  2411.  
  2412.     mesh->mtl[i] = NULL;
  2413.     }
  2414.  
  2415.     do  {
  2416.     start_chunk (&chunk);
  2417.  
  2418.     if (chunk.end <= mainchunk->end) {
  2419.         switch (chunk.tag) {
  2420.         case 0x4130: parse_msh_mat_group();
  2421.                  break;
  2422.         case 0x4150: parse_smooth_group();
  2423.                  break;
  2424.         }
  2425.     }
  2426.  
  2427.     end_chunk (&chunk);
  2428.     } while (chunk.end <= mainchunk->end);
  2429.  
  2430.     for (i = 0; i < mesh->faces; i++) {
  2431.     if (mesh->mtl[i] == NULL)
  2432.         mesh->mtl[i] = update_materials ("Default", 0);
  2433.     }
  2434. }
  2435.  
  2436.  
  2437. void parse_msh_mat_group()
  2438. {
  2439.     Material *new_mtl;
  2440.     char mtlname[80];
  2441.     int  mtlcnt;
  2442.     int  i, face;
  2443.  
  2444.     strcpy (mtlname, read_string());
  2445.     cleanup_name (mtlname);
  2446.  
  2447.     new_mtl = update_materials (mtlname, 0);
  2448.  
  2449.     mtlcnt = read_word();
  2450.  
  2451.     for (i = 0; i < mtlcnt; i++) {
  2452.     face = read_word();
  2453.     mesh->mtl[face] = new_mtl;
  2454.     }
  2455. }
  2456.  
  2457.  
  2458. void parse_smooth_group()
  2459. {
  2460.  
  2461. }
  2462.  
  2463.  
  2464. void parse_mesh_matrix()
  2465. {
  2466.     int i, j;
  2467.  
  2468.     if (mesh != NULL) {
  2469.     for (i = 0; i < 4; i++) {
  2470.         for (j = 0; j < 3; j++)
  2471.         mesh->matrix[i][j] = read_float();
  2472.     }
  2473.  
  2474.     mat_inv (mesh->invmatrix, mesh->matrix);
  2475.     }
  2476. }
  2477.  
  2478.  
  2479. void parse_n_direct_light (Chunk *mainchunk)
  2480. {
  2481.     Chunk chunk;
  2482.     Spotlight *s;
  2483.     OmniLight *o;
  2484.     int light_off = FALSE;
  2485.     int spot_flag = FALSE;
  2486.  
  2487.     read_point (pos);
  2488.     parse_colour (&col);
  2489.  
  2490.     do  {
  2491.     start_chunk (&chunk);
  2492.  
  2493.     if (chunk.end <= mainchunk->end) {
  2494.         switch (chunk.tag) {
  2495.         case 0x4620: light_off = TRUE;
  2496.                  break;
  2497.         case 0x4610: parse_dl_spotlight();
  2498.                  spot_flag = TRUE;
  2499.                  break;
  2500.         }
  2501.     }
  2502.  
  2503.     end_chunk (&chunk);
  2504.     } while (chunk.end <= mainchunk->end);
  2505.  
  2506.     if (light_off)
  2507.     return;
  2508.  
  2509.     if (!spot_flag) {
  2510.     if (frame >= 0) {
  2511.         o = LIST_FIND (omni_list, obj_name);
  2512.  
  2513.         if (o != NULL) {
  2514.         pos[X] = o->pos[X];
  2515.         pos[Y] = o->pos[Y];
  2516.         pos[Z] = o->pos[Z];
  2517.         col    = o->col;
  2518.         }
  2519.     }
  2520.  
  2521.     write_light (out, obj_name, pos, col);
  2522.     }
  2523.     else {
  2524.     if (frame >= 0) {
  2525.         s = LIST_FIND (spot_list, obj_name);
  2526.  
  2527.         if (s != NULL) {
  2528.         pos[X]    = s->pos[X];
  2529.         pos[Y]    = s->pos[Y];
  2530.         pos[Z]    = s->pos[Z];
  2531.         target[X] = s->target[X];
  2532.         target[Y] = s->target[Y];
  2533.         target[Z] = s->target[Z];
  2534.         col       = s->col;
  2535.         hotspot   = s->hotspot;
  2536.         falloff   = s->falloff;
  2537.         }
  2538.     }
  2539.  
  2540.     if (falloff <= 0.0)
  2541.         falloff = 180.0;
  2542.  
  2543.     if (hotspot <= 0.0)
  2544.         hotspot = 0.7*falloff;
  2545.  
  2546.     write_spot (out, obj_name, pos, target, col, hotspot, falloff);
  2547.     }
  2548. }
  2549.  
  2550.  
  2551. void parse_dl_spotlight()
  2552. {
  2553.     read_point (target);
  2554.  
  2555.     hotspot = read_float();
  2556.     falloff = read_float();
  2557. }
  2558.  
  2559.  
  2560. void parse_n_camera()
  2561. {
  2562.     float  bank;
  2563.     float  lens;
  2564.  
  2565.     read_point (pos);
  2566.     read_point (target);
  2567.     bank = read_float();
  2568.     lens = read_float();
  2569.  
  2570.     if (frame >= 0 && cam_list != NULL) {
  2571.     pos[X]    = cam_list->pos[X];
  2572.     pos[Y]    = cam_list->pos[Y];
  2573.     pos[Z]    = cam_list->pos[Z];
  2574.     target[X] = cam_list->target[X];
  2575.     target[Y] = cam_list->target[Y];
  2576.     target[Z] = cam_list->target[Z];
  2577.     lens      = cam_list->lens;
  2578.     bank      = cam_list->bank;
  2579.     }
  2580.  
  2581.     write_camera (out, obj_name, pos, target, lens, bank);
  2582. }
  2583.  
  2584.  
  2585. void parse_colour (Colour *colour)
  2586. {
  2587.     Chunk chunk;
  2588.     Colour_24 colour_24;
  2589.  
  2590.     start_chunk (&chunk);
  2591.  
  2592.     switch (chunk.tag) {
  2593.     case 0x0010: parse_colour_f (colour);
  2594.              break;
  2595.  
  2596.     case 0x0011: parse_colour_24 (&colour_24);
  2597.              colour->red   = colour_24.red/255.0;
  2598.              colour->green = colour_24.green/255.0;
  2599.              colour->blue  = colour_24.blue/255.0;
  2600.              break;
  2601.  
  2602.     default:     abortmsg ("Error parsing colour", 1);
  2603.     }
  2604.  
  2605.     end_chunk (&chunk);
  2606. }
  2607.  
  2608.  
  2609. void parse_colour_f (Colour *colour)
  2610. {
  2611.     colour->red   = read_float();
  2612.     colour->green = read_float();
  2613.     colour->blue  = read_float();
  2614. }
  2615.  
  2616.  
  2617. void parse_colour_24 (Colour_24 *colour)
  2618. {
  2619.     colour->red   = read_byte();
  2620.     colour->green = read_byte();
  2621.     colour->blue  = read_byte();
  2622. }
  2623.  
  2624.  
  2625. float parse_percentage()
  2626. {
  2627.     Chunk chunk;
  2628.     float percent = 0.0;
  2629.  
  2630.     start_chunk (&chunk);
  2631.  
  2632.     switch (chunk.tag) {
  2633.     case 0x0030: percent = parse_int_percentage()/100.0;
  2634.              break;
  2635.  
  2636.     case 0x0031: percent = parse_float_percentage();
  2637.              break;
  2638.  
  2639.     default:     printf ("WARNING: Error parsing percentage");
  2640.     }
  2641.  
  2642.     end_chunk (&chunk);
  2643.  
  2644.     return percent;
  2645. }
  2646.  
  2647.  
  2648. short parse_int_percentage()
  2649. {
  2650.     word percent = read_word();
  2651.  
  2652.     return percent;
  2653. }
  2654.  
  2655.  
  2656. float parse_float_percentage()
  2657. {
  2658.     float percent = read_float();
  2659.  
  2660.     return percent;
  2661. }
  2662.  
  2663.  
  2664. void start_chunk (Chunk *chunk)
  2665. {
  2666.     chunk->start  = ftell(in);
  2667.     chunk->tag    = read_word();
  2668.     chunk->length = read_dword();
  2669.     chunk->end    = chunk->start + chunk->length;
  2670. }
  2671.  
  2672.  
  2673. void end_chunk (Chunk *chunk)
  2674. {
  2675.     fseek (in, chunk->end, 0);
  2676. }
  2677.  
  2678.  
  2679. byte read_byte()
  2680. {
  2681.     byte data;
  2682.  
  2683.     data = fgetc (in);
  2684.  
  2685.     return data;
  2686. }
  2687.  
  2688.  
  2689. word read_word()
  2690. {
  2691. /*
  2692.     word data;
  2693.     fread (&data, 2, 1, in);
  2694. */  
  2695.  
  2696.     word newdata;
  2697.  
  2698.     byte byte0;
  2699.     byte byte1;
  2700.  
  2701.     byte0 = fgetc (in);
  2702.     byte1 = fgetc (in);
  2703.     
  2704.     newdata = ((((unsigned word)byte1)<<8)|((unsigned word)byte0));
  2705.   
  2706.     return newdata;
  2707. }
  2708.  
  2709.  
  2710. dword read_dword()
  2711. {
  2712. /*
  2713.     dword data;
  2714.     fread (&data, 4, 1, in);
  2715. */    
  2716.  
  2717.     dword newdata;
  2718.  
  2719.     byte byte0;
  2720.     byte byte1;
  2721.     byte byte2;
  2722.     byte byte3;
  2723.  
  2724.     byte0 = fgetc (in);
  2725.     byte1 = fgetc (in);
  2726.     byte2 = fgetc (in);
  2727.     byte3 = fgetc (in);
  2728. /*    
  2729.     newdata = ((byte3<<24)|(byte2<<16)|(byte1<<8)|byte0);
  2730. */
  2731.     newdata = ((((unsigned long)byte3)<<24)|(((unsigned long)byte2)<<16)|(((unsigned long)byte1)<<8)|((unsigned long)byte0));
  2732.  
  2733.     return newdata;
  2734. }
  2735.  
  2736.  
  2737. float read_float()
  2738. {
  2739.  
  2740. /*
  2741.     float data;
  2742.     fread (&data, 4, 1, in);
  2743.     return data;
  2744. */
  2745.  
  2746.     long data;
  2747.     float *pf;
  2748.     float value;
  2749.     
  2750.     byte byte0;
  2751.     byte byte1;
  2752.     byte byte2;
  2753.     byte byte3;
  2754.  
  2755.     byte0 = fgetc (in);
  2756.     byte1 = fgetc (in);
  2757.     byte2 = fgetc (in);
  2758.     byte3 = fgetc (in);
  2759.     
  2760.     data = ((((unsigned long)byte3)<<24)|(((unsigned long)byte2)<<16)|(((unsigned long)byte1)<<8)|((unsigned long)byte0));
  2761.     
  2762.     pf    = (float *)&data;
  2763.  
  2764.     value    = *pf;
  2765. /*
  2766.     printf ("Value: %f",value);
  2767. */    
  2768.     return value;
  2769. }
  2770.  
  2771.  
  2772.  
  2773. void read_point (Vector v)
  2774. {
  2775.     v[X] = read_float();
  2776.     v[Y] = read_float();
  2777.     v[Z] = read_float();
  2778. }
  2779.  
  2780.  
  2781. char *read_string()
  2782. {
  2783.     static char string[80];
  2784.     int i;
  2785.  
  2786.     for (i = 0; i < 80; i++) {
  2787.     string[i] = read_byte();
  2788.  
  2789.     if (string[i] == '\0')
  2790.         break;
  2791.     }
  2792.  
  2793.     return string;
  2794. }
  2795.  
  2796.  
  2797. float findfov (float lens)
  2798. {
  2799.     static float lens_table[13] =
  2800.          { 15.0, 17.0, 24.0, 35.0, 50.0, 85.0, 100.0, 135.0, 200.0,
  2801.            500.0, 625.0, 800.0, 1000.0 };
  2802.     static float fov_table[13] =
  2803.          { 115.0, 102.0, 84.0, 63.0, 46.0, 28.0, 24.0, 18.0,
  2804.            12.0, 5.0, 4.0, 3.125, 2.5 };
  2805.  
  2806.     float fov, f1, f2, l1, l2;
  2807.     int   i;
  2808.  
  2809.     if (lens < 15.0)
  2810.     lens = 15.0;
  2811.     else if (lens > 1000.0)
  2812.     lens = 1000.0;
  2813.  
  2814.     for (i = 0; i < 13; i++)
  2815.     if (lens < lens_table[i])
  2816.         break;
  2817.  
  2818.     if (i == 13)
  2819.     i = 12;
  2820.     else if (i == 0)
  2821.     i = 1;
  2822.  
  2823.     f1 = fov_table[i-1];
  2824.     f2 = fov_table[i];
  2825.     l1 = lens_table[i-1];
  2826.     l2 = lens_table[i];
  2827.  
  2828.     fov = f1 + (lens - l1) * (f2 - f1) / (l2 - l1);
  2829.  
  2830.     return fov;
  2831. }
  2832.  
  2833.  
  2834.